/******************************************************************************
Test of setting up MSP430g2553 as I2C slave

This code does two things:
1)	Blinks an LED on P1.0 on and off with a period of 1 second

2)	Listens as an I2C slave on the address set in I2C_OWN_ADDR.  
	It will respond to reads with a value that is 3x the last write.

Based (very loosely) on code written during 
Fall 2011 in ME 461 taught by S. R. Platt
*******************************************************************************/

#include "msp430g2553.h"

#define	SET_BIT8(reg, bit)		( reg |=  (0x01   << bit) )
#define	CLEAR_BIT8(reg, bit)	( reg &= ~(0x01   << bit) )
#define	SET_BIT16(reg, bit)		( reg |=  (0x0001 << bit) )
#define	CLEAR_BIT16(reg, bit)	( reg &= ~(0x0001 << bit) )

#define	I2C_OWN_ADDR	0x20		// address 0x40 -> we receive from master, 0x41 -> we write byte to I2C bus


unsigned int	inc = 1;		// debugging incremental counter

unsigned char	i2cdata = 0x00;	// scratch pad for playing with i2c info

char newprint = 0;
unsigned long timecnt = 0;

void main(void) {
	
	// stop the watchdog timer
	WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
	
	// set up internal clocking
	if (CALBC1_16MHZ ==0xFF || CALDCO_16MHZ == 0xFF) while(1);	// set up to use internal oscillator                                             
	DCOCTL = CALDCO_16MHZ;                		// Set uC to run at approximately 16 Mhz
	BCSCTL1 = CALBC1_16MHZ; 
	
	// set up status "I'm alive!" LED
	P1DIR |= 0x1;								// Default LED output - P1.0
	
	// Timer A0 Config - periodic interrupts
	TA0CCTL0 = CCIE;                           // Enable interrupt
	TA0CCR0 = 1600;                           // period = .1ms   
	TA0CTL = TASSEL_2 + MC_1;                  // source SMCLK, up mode

	// Timer A1 config - PWM
	
	
	// USCI_B config, I2C Slave
	// set CTL1 first, to keep in reset while configuring everything else
	UCB0CTL1 = 	UCTR * 0 + 			// set as receiver
				UCSWRST;			// keep in reset
				
	UCB0CTL0 = 	UCA10 * 0 +			// 0 = use 7-bit addresses for own address
				UCMST * 0 +			// 0 = we are I2C slave
				UCMODE_3 +			// I2C mode
				UCSYNC * 1;			// synchronous operation

	UCB0I2COA = (UCGCEN * 0) + I2C_OWN_ADDR;		// UCGEN = 0 -> do not respond to general call
				
	SET_BIT8(P1SEL, 7);  // on g2553, UCB0SDA -> P1.7, P1SEL.7 = 1 and P1SEL2.7 = 1
	SET_BIT8(P1SEL2, 7); 
	
	SET_BIT8(P1SEL, 6);  // on g2553, UCB0SCL -> P1SEL.6 = 1 and P1SEL2.6 = 1
	SET_BIT8(P1SEL2, 6); 

	UCB0CTL1 &= ~UCSWRST;	// take out of reset (after configuring everything but before enabling interrupts)
	
	IE2 |= UCB0TXIE | UCB0RXIE;		// enable I2C interrupts on TX and RX
		

	_BIS_SR(GIE); 						    						// Enable global interrupt

	
	while(1) {  
		if (newprint)  { 
			P1OUT ^= 0x1;		// Blink LED
			newprint = 0;
		}
	}  // while
} // main()


// Timer A0 interrupt service routine
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{

	timecnt++; // Keep track of time for main while loop. 

	if ((timecnt%5000) == 0) {  // 1/2 second
		newprint = 1;  // flag main while loop that .5 seconds have gone by.  
	}
}  // timer A ISR


// I2C RX/TX interrupt
// Note that in I2C mode the TX interrupt is used for BOTH RX and TX, and
// the RX interrupt is used for the status flags.  Sigh.
#pragma vector=USCIAB0TX_VECTOR
__interrupt void I2C_TX_RX(void)
{
	if(IFG2&UCB0TXIFG) {  // USCI_B0 requested TX interrupt (need to write a byte to UCB0TXBUF)
		UCB0TXBUF = i2cdata * 3;	// write out 3x the value in i2cdata
		IFG2 &= ~UCB0TXIFG;   // clear IFG
	}
	if(IFG2&UCB0RXIFG) {  // USCI_B0 requested RX interrupt (need to read a byte from UCB0RXBUF)
		i2cdata = UCB0RXBUF;	
		IFG2 &= ~UCB0RXIFG;   // clear IFG
	}
}

// I2C RX interrupt - in I2C slave mode this is used for status interrupts only (*not* RX!)
#pragma vector=USCIAB0RX_VECTOR
__interrupt void I2C_Status(void)
{
}
